package com.hedgehog.ratingbar;

import ohos.agp.components.AttrSet;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.element.Element;
import ohos.app.Context;

import java.math.BigDecimal;

/**
 * RatingBar
 */
public class RatingBar extends DirectionalLayout {
    private static final int STAR_COUNT = 5;

    private static final int HEIGHT_DEFAULT_VALUE = 90;

    private static final int WIDTH_DEFAULT_VALUE = 70;

    private static final int PADDING_DEFAULT_VALUE = 20;

    private static final int DIVIDE_VALUE = 2;

    private static final float ADD_VALUE = 0.5f;

    private boolean isClickable = true;

    private boolean isHalfstart = true;

    private int mStarCount;

    private int starNum;

    private OnRatingChangeListener onRatingChangeListener;

    private float starImageSize;

    private float mStarImageWidth;

    private float mStarImageHeight;

    private float mStarImagePadding;

    private Element starEmptyDrawable;

    private Element starFillDrawable;

    private Element starHalfDrawable;

    private int anInt = 1;

    private boolean isEmpty = true;
    private Context context;
    private float lastSelectedStar = 0;

    /**
     * setStarHalfDrawable
     *
     * @param starHalfDrawable StarHalfDrawable
     */
    public void setStarHalfDrawable(int starHalfDrawable) {
        this.starHalfDrawable = Utils.getElementByResId(getContext(), starHalfDrawable).get();
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListener) {
        this.onRatingChangeListener = onRatingChangeListener;
    }

    /**
     * setmClickable
     *
     * @param isClick Falg
     */
    public void setmClickable(boolean isClick) {
        this.isClickable = isClick;
    }

    /**
     * halfStar
     *
     * @param isHalfStar Falg
     */
    public void halfStar(boolean isHalfStar) {
        this.isHalfstart = isHalfStar;
    }

    /**
     * setStarFillDrawable
     *
     * @param starFillDrawable starFillDrawable
     */
    public void setStarFillDrawable(int starFillDrawable) {
        this.starFillDrawable = Utils.getElementByResId(getContext(), starFillDrawable).get();
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * setStarEmptyDrawable
     *
     * @param starEmptyDrawable starEmptyDrawable
     */
    public void setStarEmptyDrawable(int starEmptyDrawable) {
        this.starEmptyDrawable = Utils.getElementByResId(getContext(), starEmptyDrawable).get();
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * setStarImageSize
     *
     * @param starImageSize height
     */
    public void setStarImageSize(float starImageSize) {
        this.starImageSize = starImageSize;
    }

    /**
     * setStarImageWidth
     *
     * @param starImageWidth weight
     */
    public void setStarImageWidth(float starImageWidth) {
        this.mStarImageWidth = starImageWidth;
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * setStarImageHeight
     *
     * @param starImageHeight height
     */
    public void setStarImageHeight(float starImageHeight) {
        this.mStarImageHeight = starImageHeight;
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * setStarCount
     *
     * @param starCount count
     */
    public void setStarCount(int starCount) {
        this.mStarCount = starCount;
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * setImagePadding
     *
     * @param starImagePadding padding
     */
    public void setImagePadding(float starImagePadding) {
        this.mStarImagePadding = starImagePadding;
        removeAllComponents();
        createStars();
        setStar(lastSelectedStar);
    }

    /**
     * RatingBar Constructor
     *
     * @param context Context
     * @param attrs   Attributes
     */
    public RatingBar(Context context, AttrSet attrs) {
        super(context, attrs);
        this.context = context;
        setOrientation(HORIZONTAL);
        new StyledAttributes(attrs);
        starNum = 0;
        createStars();
    }

    private void createStars() {
        for (int counter = 0; counter < starNum; ++counter) {
            Image imageView = getStarImageView(context, false);
            addComponent(imageView);
        }
        for (int counter = 0; counter < mStarCount; ++counter) {
            Image imageView = getStarImageView(context, isEmpty);
            imageView.setClickedListener(component -> {
                if (isClickable) {
                    if (isHalfstart) {
                        /**
                         * This is not the best way to solve half star,
                         * but That's what We can do,Please let me know if you have better solution */
                        if (0 == anInt % DIVIDE_VALUE) {
                            setStar(getChildIndex(component) + 1f);
                        } else {
                            setStar(getChildIndex(component) + ADD_VALUE);
                        }
                        if (onRatingChangeListener != null) {
                            if (0 == anInt % DIVIDE_VALUE) {
                                onRatingChangeListener.onRatingChange(getChildIndex(component) + 1f);
                                anInt++;
                            } else {
                                onRatingChangeListener.onRatingChange(getChildIndex(component) + ADD_VALUE);
                                anInt++;
                            }
                        }
                    } else {
                        setStar(getChildIndex(component) + 1f);
                        if (onRatingChangeListener != null) {
                            onRatingChangeListener.onRatingChange(getChildIndex(component) + 1f);
                        }
                    }
                }
            });
            addComponent(imageView);
        }

    }

    /**
     * getStarImageView
     *
     * @param context Context
     * @param isNull  Flag
     * @return Image image
     */
    private Image getStarImageView(Context context, boolean isNull) {
        Image imageView = new Image(context);
        ComponentContainer.LayoutConfig para = new ComponentContainer.LayoutConfig(Math.round(mStarImageWidth),
                Math.round(mStarImageHeight));
        imageView.setLayoutConfig(para);
        imageView.setMarginLeft((int) mStarImagePadding);
        if (isNull) {
            imageView.setBackground(starEmptyDrawable);
        } else {
            imageView.setBackground(starFillDrawable);
        }
        return imageView;
    }

    /**
     * setStar
     *
     * @param starCount Star Count
     */
    public void setStar(float starCount) {
        lastSelectedStar = starCount;
        int fint = (int) starCount;
        float tempStarCount = starCount;
        BigDecimal b1 = new BigDecimal(Float.toString(tempStarCount));
        BigDecimal b2 = new BigDecimal(Integer.toString(fint));
        final float pointFlotValue = b1.subtract(b2).floatValue();
        tempStarCount = fint > this.mStarCount ? this.mStarCount : fint;
        tempStarCount = tempStarCount < 0 ? 0 : tempStarCount;

        /**
         * drawfullstar
         */
        for (int counter = 0; counter < tempStarCount; ++counter) {
            if (getComponentAt(counter) instanceof Image) {
                ((Image) getComponentAt(counter)).setBackground(starFillDrawable);
            }
        }

        /**
         * drawhalfstar
         */
        if (pointFlotValue > 0) {
            if (getComponentAt(fint) instanceof Image) {
                ((Image) getComponentAt(fint)).setBackground(starHalfDrawable);
            }
            /**
             * drawemptystar
             */
            for (int counter = this.mStarCount - 1; counter >= tempStarCount + 1; --counter) {
                if (getComponentAt(counter) instanceof Image) {
                    ((Image) getComponentAt(counter)).setBackground(starEmptyDrawable);
                }
            }
        } else {
            /**
             * drawemptystar
             */
            for (int counter = this.mStarCount - 1; counter >= tempStarCount; --counter) {
                if (getComponentAt(counter) instanceof Image) {
                    ((Image) getComponentAt(counter)).setBackground(starEmptyDrawable);
                }
            }
        }
    }

    /**
     * StyledAttributes
     */
    private class StyledAttributes {
        private String clickable = "clickable";

        private String halfstart = "halfstart";

        private String starCount = "starCount";

        private String starEmpty = "starEmpty";

        private String starFill = "starFill";

        private String starHalf = "starHalf";

        private String starImageHeight = "starImageHeight";

        private String starImageWidth = "starImageWidth";

        private String starImagePadding = "starImagePadding";

        StyledAttributes(AttrSet attrs) {
            isClickable = attrs.getAttr(clickable).isPresent() ? attrs.getAttr(clickable).get().getBoolValue() : true;
            isHalfstart = attrs.getAttr(halfstart).isPresent() ? attrs.getAttr(halfstart).get().getBoolValue() : false;
            mStarCount = attrs.getAttr(starCount).isPresent()
                    ? attrs.getAttr(starCount).get().getIntegerValue()
                    : STAR_COUNT;
            mStarImageHeight = attrs.getAttr(starImageHeight).isPresent() ? attrs.getAttr(starImageHeight)
                    .get()
                    .getIntegerValue() : HEIGHT_DEFAULT_VALUE;
            mStarImageWidth = attrs.getAttr(starImageWidth).isPresent() ? attrs.getAttr(starImageWidth)
                    .get()
                    .getIntegerValue() : WIDTH_DEFAULT_VALUE;
            mStarImagePadding = attrs.getAttr(starImagePadding).isPresent() ? attrs.getAttr(starImagePadding)
                    .get()
                    .getIntegerValue() : PADDING_DEFAULT_VALUE;
            starFillDrawable = attrs.getAttr(starFill).isPresent()
                    ? Utils.getElementByResId(getContext(), attrs.getAttr(starFill).get().getIntegerValue()).get()
                    : Utils.getElementByResId(getContext(), ResourceTable.Media_star_full).get();
            starHalfDrawable = attrs.getAttr(starHalf).isPresent()
                    ? Utils.getElementByResId(getContext(), attrs.getAttr(starHalf).get().getIntegerValue()).get()
                    : Utils.getElementByResId(getContext(), ResourceTable.Media_star_half).get();
            starEmptyDrawable = attrs.getAttr(starEmpty).isPresent()
                    ? Utils.getElementByResId(getContext(), attrs.getAttr(starEmpty).get().getIntegerValue()).get()
                    : Utils.getElementByResId(getContext(), ResourceTable.Media_star_empty).get();
        }
    }

    /**
     * change start listener
     */
    public interface OnRatingChangeListener {
        /**
         * onRatingChange
         *
         * @param ratingCount Count
         */
        void onRatingChange(float ratingCount);
    }
}
